Skip to content

[v26.1.x] sr/context: implement /contexts/{context}/... prefixed handlers#30363

Open
nguyen-andrew wants to merge 14 commits intoredpanda-data:v26.1.xfrom
nguyen-andrew:manual-backport-30189-v26.1.x-299
Open

[v26.1.x] sr/context: implement /contexts/{context}/... prefixed handlers#30363
nguyen-andrew wants to merge 14 commits intoredpanda-data:v26.1.xfrom
nguyen-andrew:manual-backport-30189-v26.1.x-299

Conversation

@nguyen-andrew
Copy link
Copy Markdown
Member

Backport of PR #30189

@nguyen-andrew nguyen-andrew added this to the v26.1.x-next milestone May 1, 2026
@nguyen-andrew nguyen-andrew added the kind/backport PRs targeting a stable branch label May 1, 2026
@nguyen-andrew nguyen-andrew self-assigned this May 1, 2026
@nguyen-andrew nguyen-andrew requested a review from pgellert May 1, 2026 02:57
@nguyen-andrew nguyen-andrew marked this pull request as ready for review May 1, 2026 02:57
@nguyen-andrew nguyen-andrew requested a review from a team as a code owner May 1, 2026 02:57
@vbotbuildovich
Copy link
Copy Markdown
Collaborator

CI test results

test results on build#83924
test_status test_class test_method test_arguments test_kind job_url passed reason test_history
FAIL debug_bundle_service_started_fixture restart_unsuccessful_run unit https://buildkite.com/redpanda/redpanda/builds/83924#019de178-b631-46b7-8a2e-359b3a2b06f8 0/1

@nguyen-andrew nguyen-andrew force-pushed the manual-backport-30189-v26.1.x-299 branch from 2ac2e11 to 37aa44f Compare May 1, 2026 21:02
Introduces context_router.h with inline helpers that will be used by
context-prefixed route wrappers:

- normalize_context(): canonicalize a URL path context parameter
    by stripping outer ':' delimiters, adding '.' prefix, and
    rejecting embedded colons (400 Bad Request via new
    context_invalid error code)
- starts_with_context(): detect subjects already qualified with
    a context prefix

Aliases like "staging", ":.staging:", and ".staging" all resolve to
the canonical form ".staging".

Includes gtest coverage for both helpers.

Includes gtest coverage for all helpers.

(cherry picked from commit cceffc0)
Adds a type-level utility for extending a std::variant with additional
alternative types without repeating the original type list. This enables
composing variant types where a superset variant needs all alternatives
from a base variant plus extras.

(cherry picked from commit c1506c2)
Splits the auth resource type into `route_resource` (route registration
time) and `resource` (authorization time). The new
`context_prefix_subject` variant in `route_resource` qualifies the
subject with the {context} path param before the ACL check runs, then
resolves to `context_subject`.

This ensures a user with ACLs on "foo" (default context) cannot access
:.staging:foo via the /contexts/.staging/subjects/foo/... URL.

(cherry picked from commit 5551d43)
Add an optional `base_path` argument to `SchemaRegistryRedpandaClient`
that, when set, is prepended to every request path. This lets tests
target context-prefixed routes such as `/contexts/.staging/...`
without modifying call sites or duplicating the client.

`SchemaRegistryEndpoints` exposes the same parameter, and `base_path`
is stored via a property that strips leading and trailing slashes so
callers can pass either form. Individual `request()` calls can also
override the configured prefix via a `base_path=` kwarg: pass `""` to
issue a single request without the prefix, or any other string to
swap it for that call.

The administrative endpoints (`status/ready`, `security/acls`,
`contexts`) are server-global and have no context-prefixed routes,
so their helpers hardcode `base_path=""` to avoid accidental
prefixing when callers have set `self.base_path` for the surrounding
test.

(cherry picked from commit 913cedb)
Registers 15 context-prefixed routes that have a {subject} path
parameter. Each route extracts the context from the URL prefix,
scopes the subject with it via scope_subject_param(), and
delegates to the existing handler.

Covers: subject CRUD, versions, compatibility, config/{subject}, and
mode/{subject} — all via /contexts/{context}/... URLs.

Includes unit tests for scope_subject_param() and ducktape coverage
for all 15 endpoints and ACL isolation.

(cherry picked from commit 0acf252)
Registers 4 context-prefixed routes for /schemas/ids/{id} and its
sub-resources (/schema, /versions, /subjects). Adds a
scope_subject_query helper that injects the context as a "subject"
query parameter, scoping schema lookups to the specified context.

Includes unit tests for scope_subject_query and ducktape coverage
for schema lookup and sub-resource queries.

(cherry picked from commit a93647d)
Adds scope_subject_prefix_query(), which injects or prepends the
normalized context into the subjectPrefix query parameter. The
context-prefixed GET /contexts/{context}/subjects route uses this
helper to scope subject listings to the specified context.

Includes unit tests for scope_subject_prefix_query and ducktape
coverage verifying subject isolation across contexts.

(cherry picked from commit c44d2c3)
Registers context-prefixed routes for context-level config/mode and
schema types:

  - GET/PUT/DELETE /contexts/{context}/config
  - GET/PUT/DELETE /contexts/{context}/mode
  - GET /contexts/{context}/schemas/types (pass-through)

Adds inject_context_as_subject(), which sets the subject path
parameter to a context-only qualified subject (e.g., ":.staging:").
The config and mode wrappers use this to delegate to the existing
config/mode subject handlers. Schema types are global so the context
is accepted for compatibility but ignored.

Includes unit tests for inject_context_as_subject and ducktape
coverage for all operations.

(cherry picked from commit 8e2b44b)
While implementing context-prefixed route handlers, noticed that
DELETE /contexts/{context} was not normalizing the context path
parameter before the default-context check.

Apply normalize_context() to the context path parameter before the
default-context check. This ensures alias forms like "staging",
":.staging:", and ".staging" all resolve to the same canonical context
for deletion.

Includes ducktape coverage cycling through alias forms.

(cherry picked from commit 7c2d3d8)
The v2.0.2 Schema Registry client stripped the path component from
URLs (confluent-kafka-go#943), preventing context-prefixed URLs
like /contexts/.serde from working. Fixed in v2.1.0 via PR redpanda-data#950.

(cherry picked from commit 18720e2)
A serde client configured with schema.registry.url pointing to
/contexts/.serde performs a full produce/consume round-trip. Verifies
schemas are registered in the target context and isolated from the
default context.

Parametrized across Python, Go, and Java clients to cover all
language ecosystems.

(cherry picked from commit cb5aff6)
Several handlers parse the {context} path parameter and feed it to
normalize_context. Pull both steps into one helper used at the route
boundary, and have the scope_subject_* helpers take an already-normalized
context (std::string_view) so a single normalize call validates the
context before any URL rewriting.

(cherry picked from commit 955d7be)
The deferred-authz helpers (handle_get_schemas_ids_id_authz,
handle_get_subjects_authz, handle_get_contexts_authz) and several
handle_config_mode_authz call sites inside the per-request handlers
hardcoded the operation nickname against the non-prefixed route's
path_description (e.g. "get_schemas_ids_id"). With the new
/contexts/{context}/... routes registered against the same handlers,
audit log records issued via these deferred paths attributed to the
wrong nickname.

Pass the route's operation_name from the wrap class through
ctx_deferred_route, the handler entry points, and into the authz
helpers so audit events record the actual route nickname (e.g.
"ctx_get_subjects" for context-prefixed requests).

(cherry picked from commit e314131)
Add an integration test that exercises four representative
/contexts/{context}/... routes — one regular handler
(POST /subjects/{subject}/versions) and three deferred handlers
(GET /subjects, GET /schemas/ids/{id}, GET /config/{subject}) — and
verifies that each audit record uses the context-prefixed nickname
(ctx_post_subject_versions, ctx_get_subjects, ctx_get_schemas_ids_id,
ctx_get_config_subject) and an authz resource scoped to the
context-qualified subject.

(cherry picked from commit bc778c4)
@nguyen-andrew nguyen-andrew force-pushed the manual-backport-30189-v26.1.x-299 branch from 37aa44f to 3316af8 Compare May 1, 2026 21:03
@nguyen-andrew
Copy link
Copy Markdown
Member Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/build area/redpanda kind/backport PRs targeting a stable branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants